package com.gitee.xmhzzz.component.openfeign.customized;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.xmhzzz.component.common.dto.CommonExceptionRes;
import com.gitee.xmhzzz.component.common.enums.ResponseCode;
import com.gitee.xmhzzz.component.common.exception.DefaultBusinessException;
import feign.FeignException;
import feign.Response;
import feign.codec.ErrorDecoder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;

import java.lang.reflect.Constructor;

public class FeignErrorDecoder extends ErrorDecoder.Default implements InitializingBean {
    /**
     * todo 是否可以共用已有的mapper
     */
    private ObjectMapper mapper;

    @Override
    public void afterPropertiesSet() {
        mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public Exception decode(String methodKey, Response response) {
        Exception exception = super.decode(methodKey, response);
        DefaultBusinessException resultException = null;
        if ((exception instanceof FeignException)) {
            try {
                resultException = resolveException((FeignException) exception);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultException != null ? resultException : exception;
    }

    private DefaultBusinessException resolveException(FeignException exception) throws Exception {
        return convertToException(parseExceptionRes(exception));
    }

    private CommonExceptionRes parseExceptionRes(FeignException exception) throws Exception {
        return mapper.readValue(exception.contentUTF8(), CommonExceptionRes.class);
    }

    private DefaultBusinessException convertToException(CommonExceptionRes res) {
        DefaultBusinessException resultException = null;
        if (StringUtils.isNotBlank(res.getException())) {
            try {
                Class<?> clazz = Class.forName(res.getException());
                Constructor<?> c = clazz.getConstructor(String.class);
                resultException = (DefaultBusinessException) c.newInstance(new Object[]{res.getMessage()});
                resultException.setResponseCode(ResponseCode.of(res.getCode()).getCode());
            } catch (Exception e) {
                resultException = new DefaultBusinessException(res.getMessage(),ResponseCode.of(res.getCode()));
            }

        }
        return resultException;
    }
}
